package com.fjwt.gz.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.symmetric.SM4;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjwt.gz.core.cache.RedisUtil;
import com.fjwt.gz.core.cache.redis.RedisDataBaseContent;
import com.fjwt.gz.core.constants.CS;
import com.fjwt.gz.core.constants.Constants;
import com.fjwt.gz.core.model.*;
import com.fjwt.gz.core.service.ISysConfigService;
import com.fjwt.gz.db.entity.SysConfig;
import com.fjwt.gz.service.mapper.SysConfigMapper;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 系统配置表 服务实现类
 * </p>
 *
 * @author [mybatis plus generator]
 * @since 2020-07-29
 */
@Service
public class SysConfigService extends ServiceImpl<SysConfigMapper, SysConfig> implements ISysConfigService {

    /** 是否启用缓存
     * true: 表示将使用内存缓存， 将部分系统配置项 或 商户应用/服务商信息进行缓存并读取
     * false: 直接查询DB
     * **/
    public static boolean IS_USE_CACHE = false;

    /** http通信是否优先使用加密数据传输 */
    public static boolean HTTP_MSG_IS_ENCRYPT = false;

    /** 密码过期是否需强制更改 */
    public static boolean PWD_EXPIRED_MUST_RESET = false;

    /** DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同，否则加解密不一致导致业务异常！] **/
    public static String DB_ENCRYPT_SECRET = null;
    public static SM4 DB_ENCRYPT_SM4 = null;

    /** web传输加解密 秘钥 (必须16位) [每个系统配置必须相同，否则加解密不一致导致业务异常！] **/
    public static String HTTP_MESSAGE_ENCRYPT_SECRET = null;
    public static SM4 HTTP_MESSAGE_ENCRYPT_SM4 = null;

    /** OSS配置参数 **/
    public static MutablePair<String, DBOSSConfig> OSS_CONFIG = new MutablePair<>("ossConfig", null);

    /** OEM 配置参数 **/
    private static MutablePair<String, DBOEMConfig> OEM_CONFIG = new MutablePair<>("oemConfig", null);

    /** 消息推送 配置参数 **/
    public static MutablePair<String, DBAppPushConfig> APP_PUSH_CONFIG = new MutablePair<>("appPushConfig", null);

    /** 隐私协议与服务政策 配置参数 **/
    private static MutablePair<String, DBTreatyConfig> TREATY_CONFIG = new MutablePair<>("treatyConfig", null);

    /** 高德地图 配置参数 **/
    public static MutablePair<String, DBApiMapConfig> API_MAP_CONFIG = new MutablePair<>("apiMapConfig", null);

    /** 系统安全 配置参数 **/
    public static MutablePair<String, DBsecurityConfig> SECURITY_CONFIG = new MutablePair<>("securityConfig", null);

    public synchronized void initDBConfig(String groupKey) {

        // 不管是否开启缓存， 此配置都需要更新。
        if(SECURITY_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            SECURITY_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBsecurityConfig.class);
            SysConfigService.HTTP_MSG_IS_ENCRYPT = SECURITY_CONFIG.right.httpMsgIsEncrypt(); //重置静态属性
            SysConfigService.PWD_EXPIRED_MUST_RESET = SECURITY_CONFIG.right.passwordExpiredIsMustModify(); //重置静态属性
        }

        // 若当前系统不缓存，则直接返回
        if(!IS_USE_CACHE){
            return;
        }

        if(OSS_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            OSS_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBOSSConfig.class);
        }else if(TREATY_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            TREATY_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBTreatyConfig.class);
        }else if(OEM_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            SysConfig sysConfig = this.getById(OEM_CONFIG.getLeft());
            OEM_CONFIG.right = sysConfig == null ? new DBOEMConfig() : JSON.parseObject(sysConfig.getConfigVal(), DBOEMConfig.class);
        }else if(APP_PUSH_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            APP_PUSH_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBAppPushConfig.class);
        }else if(API_MAP_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            API_MAP_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBApiMapConfig.class);
        }
    }

    /** 获取OSS配置参数 **/
    @Override
    public DBOSSConfig getOssConfig() {
        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(OSS_CONFIG.getLeft()).toJavaObject(DBOSSConfig.class);
        }

        if(OSS_CONFIG.getRight() == null){
            initDBConfig(OSS_CONFIG.getLeft());
        }
        return OSS_CONFIG.right;
    }

    /** 获取OSS配置参数 **/
    @Override
    public DBTreatyConfig getTreatyConfig() {
        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(TREATY_CONFIG.getLeft()).toJavaObject(DBTreatyConfig.class);
        }

        if(OSS_CONFIG.getRight() == null){
            initDBConfig(TREATY_CONFIG.getLeft());
        }
        return TREATY_CONFIG.right;
    }


    /** 获取OSS配置参数 **/
    @Override
    public DBOEMConfig getOemConfig() {
        // 查询DB
        if(!IS_USE_CACHE){
            SysConfig sysConfig = this.getById(OEM_CONFIG.getLeft());
            return sysConfig == null ? new DBOEMConfig() : JSON.parseObject(sysConfig.getConfigVal(), DBOEMConfig.class);
        }

        if(OEM_CONFIG.getRight() == null){
            initDBConfig(OEM_CONFIG.getLeft());
        }
        return OEM_CONFIG.right;
    }

    /** 获取APP  PUSH配置参数 **/
    @Override
    public DBAppPushConfig getDBAppPushConfig() {

        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(APP_PUSH_CONFIG.getLeft()).toJavaObject(DBAppPushConfig.class);
        }

        if(APP_PUSH_CONFIG.getRight() == null ){
            initDBConfig(APP_PUSH_CONFIG.getLeft());
        }
        return APP_PUSH_CONFIG.right;
    }

    /** 获取百度语音配置参数 **/
    @Override
    public DBApiMapConfig getDBApiMapConfig() {

        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(API_MAP_CONFIG.getLeft()).toJavaObject(DBApiMapConfig.class);
        }

        if(API_MAP_CONFIG.getRight() == null ){
            initDBConfig(API_MAP_CONFIG.getLeft());
        }
        return API_MAP_CONFIG.right;
    }

    @Override
    public DBsecurityConfig getDBSecurityConfig() {
        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(SECURITY_CONFIG.getLeft()).toJavaObject(DBsecurityConfig.class);
        }

        if(SECURITY_CONFIG.getRight() == null ){
            initDBConfig(SECURITY_CONFIG.getLeft());
        }
        return SECURITY_CONFIG.right;
    }

    @Override
    public SM4 getHttpMessageSM4() {
        return HTTP_MESSAGE_ENCRYPT_SM4;
    }

    /** 根据分组查询，并返回JSON对象格式的数据 **/
    public JSONObject selectByGroupKey(String groupKey){

        JSONObject result = new JSONObject();
        list(SysConfig.gw().select(SysConfig::getConfigKey, SysConfig::getConfigVal).eq(SysConfig::getGroupKey, groupKey))
        .stream().forEach(item -> result.put(item.getConfigKey(), item.getConfigVal()));
        return result;
    }


    public int updateByConfigKey(Map<String, String> updateMap) {
        int count = 0;
        Set<String> set = updateMap.keySet();
        for(String k : set) {
            SysConfig sysConfig = new SysConfig();
            sysConfig.setConfigKey(k);
            sysConfig.setConfigVal(updateMap.get(k));
            boolean update = saveOrUpdate(sysConfig);
            if (update) {
                count ++;
            }
        }
        return count;
    }

    /** 查询密码原文 **/
    public String queryDefaultPasswordRaw(){
        return Base64.decodeStr(getById("defaultPassword").getConfigVal());
    }


    /** 查询是否需要预审核 */
    public boolean queryMchApplymentPreAudit(){
        return "1".equals(this.getById("mchApplymentPreAudit").getConfigVal());
    }

    /**
     * 查询三方通道配置信息
     */
    public String getIfCode(String ifCode){
        String payIfCode = CS.getPayIfCode(ifCode);
        String authConfig;
        authConfig = RedisUtil.getString(payIfCode);
        if (ObjectUtils.isEmpty(authConfig)) {
            SysConfig sysConfig = baseMapper.selectById(ifCode);
            authConfig = sysConfig.getConfigVal();
            RedisUtil.set(payIfCode, authConfig);
        }
        return authConfig;
    }

    public <T> T getDbRedisByConfigKey(Class<T> clazz, String key) {
        String aliPushConfig = RedisUtil.getString(RedisDataBaseContent.REDIS_TEMPLATE_MCHORDER, "resource:config:"+key);
        if (StringUtils.isNotBlank(aliPushConfig)){
            return com.alibaba.fastjson.JSONObject.parseObject(aliPushConfig, clazz);
        }
        SysConfig sysConfig = this.getById(key);
        String jsonString = sysConfig.getConfigVal();
        RedisUtil.setString(RedisDataBaseContent.REDIS_TEMPLATE_MCHORDER, "resource:config:"+key, jsonString, 1, TimeUnit.HOURS);
        return com.alibaba.fastjson.JSONObject.parseObject(jsonString, clazz);
    }

    public <T> T getDbRedisByLikeConfigVal(Class<T> clazz, String key) {
        String aliPushConfig = RedisUtil.getString(RedisDataBaseContent.REDIS_TEMPLATE_MCHORDER, "resource:config:"+key);
        if (StringUtils.isNotBlank(aliPushConfig)){
            return com.alibaba.fastjson.JSONObject.parseObject(aliPushConfig, clazz);
        }
        LambdaQueryWrapper<SysConfig> gw = SysConfig.gw();
        gw.like(SysConfig::getConfigVal, key);
        SysConfig sysConfig = getOne(gw);
//        String jsonString = sysConfig.getConfigVal();
        RedisUtil.setString(RedisDataBaseContent.REDIS_TEMPLATE_MCHORDER, "resource:config:"+key, JSON.toJSONString(sysConfig), 1, TimeUnit.HOURS);
        return com.alibaba.fastjson.JSONObject.parseObject(JSON.toJSONString(sysConfig), clazz);
    }

    /**
     * 获取系统配置列表
     * @return
     */
    public List<SysConfig> getSysConfigList() {
        LambdaQueryWrapper<SysConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysConfig::getGroupKey, Constants.POINT.POINT_PRODUCE);
        List<SysConfig> list = this.baseMapper.selectList(queryWrapper);
        return list;
    }
}
